﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.GZip;

namespace mlnx_os_sysdump_analyzer
{
    class Methods
    {
        //
        //----------------------------------------------------
        /// <summary>
        /// static function, get value from hex number starting from a specific offset and size.
        /// </summary>
        /// <param name="hexNum">hex number</param>
        /// <param name="offset">offset of the required value</param>
        /// <param name="size">number of bits to read (staring from the offset)</param>
        /// <returns></returns>
        public static string GetValueFromOffset(string hexNum, int offset, int size)
        {
            try
            {
                /// check the input
                if (hexNum != null && hexNum != "")
                {
                    /// parse the hex num to int
                    int decNum = Int32.Parse(Hex2decString(hexNum));
                    /// shift the number to the desirede offset
                    decNum = decNum >> offset;
                    /// prepare a mask (which bits to read)
                    int mask = 0;
                    while (size > 0)
                    {
                        mask = mask << 1;
                        mask = mask | 1;
                        size--;
                    }
                    /// read 'size' bits
                    decNum = decNum & mask;
                    /// return the value as string
                    return decNum.ToString("X");
                }
                else
                {
                    return "";
                }
            }
            catch
            {
                return "";
            }
        }
        //
        //----------------------------------------------------
        /// <summary>
        /// converts hex number to decemal number (in string representation).
        /// </summary>
        /// <param name="hex2decNoWS">hex number</param>
        /// <returns></returns>
        public static String Hex2decString(String hex2decNoWS)
        {
            /// check input
            if (hex2decNoWS != null && hex2decNoWS != "")
            {
                /// remove white spaces 
                hex2decNoWS = hex2decNoWS.Replace(" ", "");
                hex2decNoWS = hex2decNoWS.Replace("\\s+", "");
                hex2decNoWS = hex2decNoWS.Replace("0x", "");
                /// return the decimal value
                return Int32.Parse(hex2decNoWS, System.Globalization.NumberStyles.HexNumber).ToString();
            }
            else
            {
                return "";
            }
        }
        //
        //----------------------------------------------------
        //
        /// <summary>
        /// decompress tgz file
        /// </summary>
        /// <param name="compressedFilePath">'tgz' file to be decompressed</param>
        /// <param name="targetDir">folder to save the content of the compressed file</param>
        /// <returns></returns>
        public static Boolean ExtractTarFile(string compressedFilePath, string targetDir)
        {
            byte[] dataBuffer = new byte[4096];
            Stream inStream = null;
            ICSharpCode.SharpZipLib.Tar.TarArchive tarArchiv = null;
            try
            {

                try
                {
                    inStream = File.OpenRead(compressedFilePath);
                    inStream = new GZipInputStream(inStream);

                    tarArchiv = ICSharpCode.SharpZipLib.Tar.TarArchive.CreateInputTarArchive(inStream);
                    tarArchiv.ExtractContents(targetDir);
                }
                catch
                {
                    return false;
                }
            }
            catch
            { }
            if (inStream != null)
            {
                inStream.Dispose();

            }
            if (tarArchiv != null)
            {
                tarArchiv.Dispose();
            }
            return true;
        }
        //
        //----------------------------------------------------
        /// <summary>
        /// delete folder and its content 
        /// </summary>
        /// <param name="targetDir">folder to delete</param>
        public static void DeleteFolderRec(string targetDir)
        {
            try
            {
                DirectoryInfo di = new DirectoryInfo(targetDir);
                /// delete all files in the folder
                foreach (FileInfo file in di.GetFiles())
                {
                    try
                    {
                        file.Delete();
                    }
                    catch { }
                }
                /// recursive call for all the sub-folders
                foreach (DirectoryInfo subfolder in di.GetDirectories())
                {
                    DeleteFolderRec(subfolder.FullName);
                }
                /// delete the current folder
                di.Delete();
            }
            catch { }
        }
        //
        //----------------------------------------------------
        /// <summary>
        /// recursive search for a file
        /// </summary>
        /// <param name="targetDir">target folder</param>
        /// <param name="fileName">file name</param>
        /// <returns></returns>
        public static string FindFileRec(string targetDir, string fileName)
        {
            DirectoryInfo di = new DirectoryInfo(targetDir);
            try
            {
                /// check all the files
                foreach (FileInfo file in di.GetFiles())
                {
                    /// check if the file is in the current folder
                    if (file.Name.Equals(fileName))
                    {
                        return file.FullName;
                    }
                }
                /// recursive call for all the sub-folders
                foreach (DirectoryInfo subfolder in di.GetDirectories())
                {
                    string res = FindFileRec(subfolder.FullName, fileName);
                    /// if the file was found in the last recursive call, then stop and return its path.
                    if (res != null)
                    {
                        return res;
                    }
                }
            }
            catch { }
            return null;
        }
        //
        //----------------------------------------------------
        /// <summary>
        /// convert hex number to the ASCII character that it represents.
        /// </summary>
        /// <param name="hexString">hex number</param>
        /// <returns></returns>
        public static string HexToAscii(string hexString)
        {
            /// check input
            if (!hexString.Equals("0") && hexString != "")
            {
                /// return ASCII character
                return System.Convert.ToChar(System.Convert.ToUInt32(hexString, 16)).ToString();
            }
            else
            {
                return "";
            }
        }
        //
        //----------------------------------------------------
        //
        /// <summary>
        /// decompress gz file
        /// </summary>
        /// <param name="compressedFilePath">'gz' file to be decompressed</param>
        /// <param name="targetDir">folder to save the content of the compressed file</param>
        /// <returns></returns>
        public static Boolean ExtractGzFile(string compressedFilePath, string targetDir)
        {
            GZipInputStream gzipStream = null;
            try
            {
                byte[] dataBuffer = new byte[4096];
                using (System.IO.Stream fs = new FileStream(compressedFilePath, FileMode.Open, FileAccess.Read))
                {
                    gzipStream = new GZipInputStream(fs);

                    // Change this to your needs
                    string fnOut = Path.Combine(targetDir, Path.GetFileNameWithoutExtension(compressedFilePath));
                    if (!Directory.Exists(targetDir))
                    {
                        Directory.CreateDirectory(targetDir);
                    }
                    using (FileStream fsOut = File.Create(fnOut))
                    {
                        StreamUtils.Copy(gzipStream, fsOut, dataBuffer);
                        fsOut.Dispose();
                    }
                }
            }
            catch (ThreadAbortException)
            {
                if (gzipStream != null)
                {
                    gzipStream.Dispose();
                }
            }
            catch
            {
                return false;
            }
            return true;
        }
        //
        //----------------------------------------------------
        /// <summary>
        /// get a value from a dictionary with checking if the key exists in the provided dictionary
        /// </summary>
        /// <param name="dic">dictionary</param>
        /// <param name="key">key</param>
        /// <returns></returns>
        public static string SafeDicGetter(Dictionary<string, string> dic, string key)
        {
            /// input check
            if (dic != null && key != null)
            {
                try
                {
                    /// check if the key exists in the dictionary
                    if (dic.ContainsKey(key) == true)
                    {
                        /// return the value
                        return dic[key];
                    }
                }
                catch { }
            }
            return "";
        }
        //
        //----------------------------------------------------
        /// <summary>
        /// get the content of a file
        /// </summary>
        /// <param name="filePath">file path</param>
        /// <param name="KEEP_RUNNING">falg to stop the function</param>
        /// <returns></returns>
        public static string GetFileContent(string filePath, ref bool KEEP_RUNNING)
        {
            /// input check
            if (!File.Exists(filePath))
                return "";
            StreamReader sr = new StreamReader(filePath);
            StringBuilder content = new StringBuilder();
            try
            {
                while (KEEP_RUNNING && sr.Peek() >= 0)
                {
                    /// read line
                    string line = sr.ReadLine();
                    /// remove un-printable characters
                    line = Regex.Replace(line, "[\x01-\x1F]", " ");
                    line = Regex.Replace(line, "[\x80-\xFF]", " ");
                    /// add new line
                    content.Append(line + "\r\n");
                }
            }
            catch
            { }
            sr.Dispose();
            return content.ToString();
        }
        //
        //----------------------------------------------------
        /// <summary>
        /// Remove Extra Spaces from a string (make sure there is at most one whire space between each two words).
        /// </summary>
        /// <param name="str">string</param>
        /// <returns></returns>
        public static string RemoveExtraSpaces(string str)
        {
            /// input check
            if (str == null)
                return "";
            // make sure we have only one space between each to columns
            while (str.Contains("  "))
            {
                str = Regex.Replace(str, "  ", " ");
            }
            return str;
        }
        //
        //----------------------------------------------------
        /// <summary>
        /// find a folder and get list of files that it contains.
        /// </summary>
        /// <param name="dirPath">main directoy path</param>
        /// <param name="targetDirName">target folder name</param>
        /// <returns></returns>
        public static ArrayList GetFileListInDir(string dirPath, string targetDirName)
        {
            DirectoryInfo di = new DirectoryInfo(dirPath);
            try
            {  
                /// is this the folder that we are looking for?
                if (di.Name.Equals(targetDirName))
                {
                    ArrayList al = new ArrayList();
                    /// get a list of the files in this folder
                    foreach (FileInfo file in di.GetFiles())
                    {
                        al.Add(new Item(file.Name, file.FullName));
                    }
                    /// return the list 
                    return al;
                }
                foreach (DirectoryInfo subfolder in di.GetDirectories())
                {
                    /// recursive call
                    ArrayList res = GetFileListInDir(subfolder.FullName, targetDirName); ;
                    /// if the last call found the folder, then return the list of files.
                    if (res != null)
                    {
                        return res;
                    }
                }
            }
            catch { }
            return null;
        }
        //
        //----------------------------------------------------
        /// <summary>
        /// round double number to 2 digits after the decimal point.
        /// </summary>
        /// <param name="d">the double number</param>
        /// <returns></returns>
        public static double RoundDoubleDigits(double d)
        {
            return double.Parse(String.Format("{0:0.00}", d));
        }
        //
        //----------------------------------------------------
        /// <summary>
        /// run a process
        /// </summary>
        /// <param name="fileName">process/url to run</param>
        public static void RunProcess(string fileName)
        {
            try
            {
                Process pr = new Process();
                pr.StartInfo.UseShellExecute = true;
                /// set the file name to run
                pr.StartInfo.FileName = fileName;
                pr.Start();
            }
            catch { }
        }
        //
        //----------------------------------------------------
        /// <summary>
        /// convert a time to DateTime object.
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public static DateTime StringToDateTime(string time)
        {// add support for this format 1/12/2012 10:10:06 AM
            try
            {
                string[] arr = Regex.Split(time, " ");
                int month = 0;
                int day = 0;
                int hour = 0;
                int min = 0;
                int sec = 0;
                int year = 2012;
                /// get the month
                switch (arr[0])
                {
                    case "Jan":
                        month = 1;
                        break;
                    case "Feb":
                        month = 2;
                        break;
                    case "Mar":
                        month = 3;
                        break;
                    case "Apr":
                        month = 4;
                        break;
                    case "May":
                        month = 5;
                        break;
                    case "Jun":
                        month = 6;
                        break;
                    case "Jul":
                        month = 7;
                        break;
                    case "Aug":
                        month = 8;
                        break;
                    case "Sep":
                        month = 9;
                        break;
                    case "Oct":
                        month = 10;
                        break;
                    case "Nov":
                        month = 11;
                        break;
                    case "Dec":
                        month = 12;
                        break;
                }
                if (month == 0)
                {
                    // the format is: 1/12/2012 10:10:06 AM
                    string[] tmpArr = Regex.Split(arr[0], "/");
                    month = Int32.Parse(tmpArr[0]);
                    day = Int32.Parse(tmpArr[1]);
                    year = Int32.Parse(tmpArr[2]);

                    tmpArr = Regex.Split(arr[1], ":");
                    hour = Int32.Parse(tmpArr[0]);
                    min = Int32.Parse(tmpArr[1]);
                    sec = Int32.Parse(tmpArr[2]); 
                }
                else
                {
                    /// get the day
                    day = Int32.Parse(arr[1]);
                    arr = Regex.Split(arr[2], ":");
                    /// get the time
                    hour = Int32.Parse(arr[0]);
                    min = Int32.Parse(arr[1]);
                    sec = Int32.Parse(arr[2]);
                }
                /// return the DateTime object that represents the input time
                DateTime res = new DateTime(year, month, day, hour, min, sec);
                return res;
            }
            catch
            {
                return DateTime.Now;
            }
        }
        //
        //----------------------------------------------------
        /// <summary>
        /// Get the Switch's Profile (Eth or IB).
        /// [if the ethinfo.txt file exists then the profile is Eth, otherwise it's IB].
        /// </summary>
        /// <param name="OUTPUT_DIR_PATH">the folder that contains the extracted sysdump file.</param>
        /// <returns></returns>
        public static string GetSwitchProfile(string OUTPUT_DIR_PATH)
        {
            if (Methods.FindFileRec(OUTPUT_DIR_PATH, "ethinfo.txt") != null)
            {
                return "Eth";
            }
            else
            {
                return "IB";
            }
        }
        //
        //----------------------------------------------------
        
        /// <summary>
        /// sorts an ArrayList of ErrorsFields
        /// </summary>
        /// <param name="list">ref to the list</param>
        public static void sortErrorsFieldsArrayList(ref ArrayList list)
	    {
	    	try
	    	{
	        	SortedDictionary<int, ErrorsFields> sortedDic = new SortedDictionary<int, ErrorsFields>();
	        	for (int i = 0; i < list.Count; i++)
	        	{
        			ErrorsFields item = (ErrorsFields)list[i];
        			int index = 0;
        			if (item.fileName.Contains(".gz"))
        			{
        				index = Int32.Parse(Regex.Split(item.fileName, @"\.")[1]);
        			}
    				sortedDic.Add(index, item);
	        	}
	        	// creat sorted list
	        	ArrayList sortedlist = new ArrayList();
	        	foreach (KeyValuePair<int, ErrorsFields> kvp in sortedDic)
	        	{
	        		sortedlist.Add(kvp.Value);
	        	}
	        	// update the list
	        	list = sortedlist;
	    	}
	    	catch	{  	}
	    }
        //
        //----------------------------------------------------

        /// <summary>
        /// Escape Like Value for data view filter 
        /// </summary>
        /// <param name="valueWithoutWildcards"></param>
        /// <returns></returns>
        public static string EscapeLikeValue(string valueWithoutWildcards)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < valueWithoutWildcards.Length; i++)
            {
                char c = valueWithoutWildcards[i];
                if (c == '*' || c == '%' || c == '[' || c == ']')
                    sb.Append("[").Append(c).Append("]");
                else if (c == '\'')
                    sb.Append("''");
                else
                    sb.Append(c);
            }
            return sb.ToString();
        }
        //
        //----------------------------------------------------
    }
}
